package com.nmc.webapp.action;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import org.springframework.mail.MailException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import com.nmc.common.Constants;
import com.nmc.common.RolesEnum;
import com.nmc.common.UserTypeEnum;
import com.nmc.service.manager.UserExistsException;
import com.nmc.service.model.Hospital;
import com.nmc.service.model.LabelValue;
import com.nmc.service.model.Role;
import com.nmc.service.model.User;
import com.nmc.service.model.Zones;
import com.nmc.webapp.util.RequestUtil;
import com.nmc.webapp.util.Util;
import com.opensymphony.xwork2.Preparable;

/**
 * Action for facilitating User Management feature.
 */
public class UserAction extends BaseAction implements Preparable {
    private static final long serialVersionUID = 6776558938712115191L;
    private List<User> users;
    private User user;
    private String id;
    private String query;
  
    /**
     * Grab the entity from the database before populating with request parameters
     */
    public void prepare() {
        // prevent failures on new
        if (getRequest().getMethod().equalsIgnoreCase("post") && (!"".equals(getRequest().getParameter("user.id")))) {
            user = userManager.getUser(getRequest().getParameter("user.id"));
        }
    }

    /**
     * Holder for users to display on list screen
     *
     * @return list of users
     */
    public List<User> getUsers() {
        return users;
    }

    public void setId(String id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public void setQ(String q) {
        this.query = q;
    }

    /**
     * Delete the user passed in.
     *
     * @return success
     */
    public String delete() {
        userManager.removeUser(user.getId().toString());
        List<Object> args = new ArrayList<Object>();
        args.add(user.getFullName());
        saveMessage(getText("user.deleted", args));

        return SUCCESS;
    }

    /**
     * Grab the user from the database based on the "id" passed in.
     *
     * @return success if user found
     * @throws IOException can happen when sending a "forbidden" from response.sendError()
     */
    public String edit() throws IOException {
        HttpServletRequest request = getRequest();
        boolean editProfile = (request.getRequestURI().indexOf("editProfile") > -1);

        // if URL is "editProfile" - make sure it's the current user
        if (editProfile && ((request.getParameter("id") != null) || (request.getParameter("from") != null))) {
            ServletActionContext.getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
            log.warn("User '" + request.getRemoteUser() + "' is trying to edit user '" +
                    request.getParameter("id") + "'");
            return null;
        }

        // if a user's id is passed in
        if (id != null) {
            // lookup the user using that id
            user = userManager.getUser(id);
        } else if (editProfile) {
            user = userManager.getUserByUsername(request.getRemoteUser());
        } else {
            user = new User();
            user.addRole(new Role(Constants.USER_ROLE));
        } 

        if (user.getUsername() != null) {
            user.setConfirmPassword(user.getPassword());

            // if user logged in with remember me, display a warning that they can't change passwords
            log.debug("checking for remember me login...");

            AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
            SecurityContext ctx = SecurityContextHolder.getContext();

            if (ctx != null) {
                Authentication auth = ctx.getAuthentication();

                if (resolver.isRememberMe(auth)) {
                    getSession().setAttribute("cookieLogin", "true");
                    saveMessage(getText("userProfile.cookieLogin"));
                }
            }
        }

        return SUCCESS;
    }
    
	public String changePwd() {
		HttpServletRequest request = getRequest();
		try {
			User dbUser = null;
			// if a user's id is passed in
			if (id != null) {
				// lookup the user using that id
				dbUser = userManager.getUser(id);
			} else {
				dbUser = userManager.getUserByUsername(request.getRemoteUser());
				user.setId(dbUser.getId());
			}
			userManager.changePassword(user);
			try {
			// add success messages
			List<Object> args = new ArrayList<Object>();
			user.setUsername(request.getRemoteUser());
			user.setEmail(dbUser.getEmail()); 
			args.add(user.getUsername());
			// Send an account information e-mail
			mailMessage.setSubject(getText("change.password.changed.successfully"));
			
				sendUserMessage(user, getText("change.password.changed.successfully", args),
						RequestUtil.getAppURL(getRequest()));
			} catch (Exception me) {
				//addActionError(me.getCause().getLocalizedMessage());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			addActionError(getText("change.password.error.message"));
			return INPUT;
		}
		return SUCCESS;
	}

    public String changePwdForm(){
    	
    	return SUCCESS;
    }

    /**
     * Default: just returns "success"
     *
     * @return "success"
     */
    public String execute() {
        return SUCCESS;
    }

    /**
     * Sends users to "mainMenu" when !from.equals("list"). Sends everyone else to "cancel"
     *
     * @return "mainMenu" or "cancel"
     */
    public String cancel() {
        if (!"list".equals(from)) {
            return "mainMenu";
        }
        return "cancel";
    }

    /**
     * Save user
     *
     * @return success if everything worked, otherwise input
     * @throws Exception when setting "access denied" fails on response
     */
    public String save() throws Exception {

        Integer originalVersion = user.getVersion();

        boolean isNew = ("".equals(getRequest().getParameter("user.version")));
        // only attempt to change roles if user is admin
        // for other users, prepare() method will handle populating
        if (getRequest().isUserInRole(Constants.ADMIN_ROLE)) {
            user.getRoles().clear(); // APF-788: Removing roles from user doesn't work
            String roleName = null;
            if(UserTypeEnum.Admin.toString().equals(user.getUserType())){
            	roleName = RolesEnum.ROLE_ADMIN.toString();
            }
			if (UserTypeEnum.Hospital.toString().equals(user.getUserType())) {
				roleName = RolesEnum.ROLE_HOSPITAL.toString();
			}
			if (UserTypeEnum.ZoneBirth.toString().equals(user.getUserType())) {
				roleName = RolesEnum.ROLE_ZONE_BIRTH.toString();
			}
			if (UserTypeEnum.ZoneDeath.toString().equals(user.getUserType())) {
				roleName = RolesEnum.ROLE_ZONE_DEATH.toString();
			}
			//String roleName = userRoles[i];
             user.addRole(roleManager.getRole(roleName));
             
//            String[] userRoles = getRequest().getParameterValues("roles");
//
//            for (int i = 0; userRoles != null && i < userRoles.length; i++) {
//                String roleName = userRoles[i];
//                user.addRole(roleManager.getRole(roleName));
//            }
        }

        try {
        	String password =  Util.randomAlphanumeric(Constants.RANDOM_COUNT);
        	if(isNew) {
        		user.setPassword(password);
        		user.setConfirmPassword(password);
        	}
            userManager.saveUser(user);
        } catch (AccessDeniedException ade) {
            // thrown by UserSecurityAdvice configured in aop:advisor userManagerSecurity
            log.warn(ade.getMessage());
            getResponse().sendError(HttpServletResponse.SC_FORBIDDEN);
            return null;
        } catch (UserExistsException e) {
            List<Object> args = new ArrayList<Object>();
            args.add(user.getUsername());
            args.add(user.getEmail());
            addActionError(getText("errors.existing.user", args));

            // reset the version # to what was passed in
            user.setVersion(originalVersion);
            // redisplay the unencrypted passwords
            user.setPassword(user.getConfirmPassword());
            return INPUT;
        }

        if (!"list".equals(from)) {
            // add success messages
            saveMessage(getText("user.saved"));
            return "mainMenu";
        } else {
            // add success messages
            List<Object> args = new ArrayList<Object>();
            args.add(user.getFullName());
            if (isNew) {
                saveMessage(getText("user.added", args));
                // Send an account information e-mail
                mailMessage.setSubject(getText("signup.email.subject"));
                try {
                    sendUserMessage(user, getText("newuser.email.message", args), RequestUtil.getAppURL(getRequest()));
                } catch (MailException me) {
                    addActionError(me.getCause().getLocalizedMessage());
                }
                return SUCCESS;
            } else {
                saveMessage(getText("user.updated.byAdmin", args));
                return INPUT;
            }
        }
    }

    /**
     * Fetch all users from database and put into local "users" variable for retrieval in the UI.
     *
     * @return "success" if no exceptions thrown
     */
    public String list() {
        users = userManager.search(query);
        return SUCCESS;
    }

    List<LabelValue> userTypeList =  null ;
    private List<Zones> zonesList = null;
    private List<Hospital> hospitalsList = null;
    private String userType;
    
    public List<LabelValue> getUserTypeList(){
    	if(userTypeList == null){
    		userTypeList = new ArrayList<LabelValue>();
    		LabelValue labelValue = new LabelValue(UserTypeEnum.Admin.name(),UserTypeEnum.Admin.name());
    		userTypeList.add(labelValue);
    		labelValue = new LabelValue(UserTypeEnum.Hospital.name(),UserTypeEnum.Hospital.name());
    		/*userTypeList.add(labelValue);
    		labelValue = new LabelValue(UserTypeEnum.User.name(),UserTypeEnum.User.name());*/
    		userTypeList.add(labelValue);
    		labelValue = new LabelValue(UserTypeEnum.ZoneBirth.name(),UserTypeEnum.ZoneBirth.name());
    		userTypeList.add(labelValue);
    		labelValue = new LabelValue(UserTypeEnum.ZoneDeath.name(),UserTypeEnum.ZoneDeath.name());
    		userTypeList.add(labelValue);
    	}
    	return userTypeList;
    }
    
    
    public List<Zones> getZones() {
		if(zonesList == null){
			zonesList = zonesManager.getZoness();
		}
		return zonesList;
	}
    
    public void setHospitalsList(List<Hospital> hospitalsList) {
		this.hospitalsList = hospitalsList;
	}

	public List<Hospital> getHospitalsList() {
		if(hospitalsList == null){
			hospitalsList = hospitalManager.getHospitals();
		}
		return hospitalsList;
	}

	public void setUserType(String userType) {
		this.userType = userType;
	}

	public String getUserType() {
		return userType;
	}

	
    
}
